

#include "cassert.h"
#include "module.h"


#define PRINT_BUF (200)


#define LPUART_TX_PORT 						GPIOB
#define LPUART_TX_PIN						LL_GPIO_PIN_4
#define LPUART_TX_AF						LL_GPIO_AF_0
#define LL_GPIO_SetAFPin_LPUART_TX()                            LL_GPIO_SetAFPin_0_7(LPUART_TX_PORT, LPUART_TX_PIN, LPUART_TX_AF)
#define LPUART_RX_PORT 						GPIOB
#define LPUART_RX_PIN						LL_GPIO_PIN_5
#define LPUART_RX_AF						LL_GPIO_AF_0
#define LL_GPIO_SetAFPin_LPUART_RX()                            LL_GPIO_SetAFPin_0_7(LPUART_RX_PORT, LPUART_RX_PIN, LPUART_RX_AF)
#define LL_EnableClock_LPUART()                                 LL_APB1_EnableClock(LL_APB1_PERIPH_LPUART)
#define LL_EnableClock_LPUART_TX_PORT()                         LL_AHB_EnableClock(LL_AHB_PERIPH_GPIOA)
#define LL_EnableClock_LPUART_RX_PORT()                         LL_AHB_EnableClock(LL_AHB_PERIPH_GPIOA)



/**
* @brief  This function configures LPUART1.
* @note   This function is used to :
*         -1- Enable GPIO clock and configures the LPUART1 pins.
*         -2- NVIC Configuration for LPUART1 interrupts.
*         -3- Enable the LPUART1 peripheral clock and clock source.
*         -4- Configure LPUART1 functional parameters.
*         -5- Enable LPUART1.
* @note   Peripheral configuration is minimal configuration from reset values.
*         Thus, some useless LL unitary functions calls below are provided as
*         commented examples - setting is default configuration from reset.
* @param  None
* @retval None
*/
void Configure_LPUART1(void)
{
  /* (1) Enable GPIO clock and configures the LPUART1 pins *******************/
  
  /* Enable the peripheral clock of GPIOB */
  LL_EnableClock_LPUART();
  LL_EnableClock_LPUART_TX_PORT();
  //LL_EnableClock_LPUART_RX_PORT();
  
  /* Configure TX Pin as : Alternate function, High Speed, PushPull, No-Pull */
  LL_GPIO_SetPinMode(LPUART_TX_PORT, LPUART_TX_PIN, LL_GPIO_MODE_ALTERNATE);
  LL_GPIO_SetAFPin_LPUART_TX();
  LL_GPIO_SetPinSpeed(LPUART_TX_PORT, LPUART_TX_PIN, LL_GPIO_SPEED_FREQ_HIGH);
  LL_GPIO_SetPinOutputType(LPUART_TX_PORT, LPUART_TX_PIN, LL_GPIO_OUTPUT_PUSHPULL);
  LL_GPIO_SetPinPull(LPUART_TX_PORT, LPUART_TX_PIN, LL_GPIO_PULL_NO);
  
  /* Configure RX Pin as : Alternate function, High Speed, PushPull, No-Pull */
//  LL_GPIO_SetPinMode(LPUART_RX_PORT, LPUART_RX_PIN, LL_GPIO_MODE_ALTERNATE);
//  LL_GPIO_SetAFPin_LPUART_RX();
//  LL_GPIO_SetPinSpeed(LPUART_RX_PORT, LPUART_RX_PIN, LL_GPIO_SPEED_FREQ_HIGH);
//  LL_GPIO_SetPinOutputType(LPUART_RX_PORT, LPUART_RX_PIN, LL_GPIO_OUTPUT_PUSHPULL);
//  LL_GPIO_SetPinPull(LPUART_RX_PORT, LPUART_RX_PIN, LL_GPIO_PULL_NO);
  
  /* (2) NVIC Configuration for LPUART1 interrupts */
  /*  - Set priority for LPUART1_IRQn */
  /*  - Enable LPUART1_IRQn           */
  NVIC_SetPriority(LPUART1_IRQn, IRQ_HIGH_PRIORITY);
  NVIC_EnableIRQ(LPUART1_IRQn);
  
  /* (4) Configure LPUART1 functional parameters ********************************/
  
#if defined(CONFIG_DEVICE_BLUENRG_LPS)
  /* Set LPUART Clock source */
  if(LL_RCC_LSE_IsEnabled())
  {
    //LL_RCC_SetLPUARTClockSource(LL_RCC_LPUCLKSEL_LSE);
		LL_RCC_SetLPUARTClockSource(LL_RCC_LPUCLKSEL_16M);
  }
  else
  {
    LL_RCC_SetLPUARTClockSource(LL_RCC_LPUCLKSEL_16M);
  }
#endif
  
  /* TX/RX direction */
  LL_LPUART_SetTransferDirection(LPUART1, LL_LPUART_DIRECTION_TX);
  
  /* 8 data bit, 1 start bit, 1 stop bit, no parity */
  LL_LPUART_ConfigCharacter(LPUART1, LL_LPUART_DATAWIDTH_8B, LL_LPUART_PARITY_NONE, LL_LPUART_STOPBITS_1);
  
  /* No Hardware Flow control */
  /* Reset value is LL_USART_HWCONTROL_NONE */
  // LL_LPUART_SetHWFlowCtrl(LPUART1, LL_USART_HWCONTROL_NONE);
  
  /* Set Baudrate to 9600 using HSI frequency set to HSI_VALUE */
  LL_LPUART_SetBaudRate(LPUART1, LL_LPUART_PRESCALER_DIV1, 115200); 
  
  LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1);  
  
  /* (5) Enable LPUART1 **********************************************************/
  LL_LPUART_Enable(LPUART1);
}

void COMPrintf_init(void)
{
  Configure_LPUART1();
}


/**
* @brief  Send Txt information message on LPUART Tx line (to PC Com port).
* @param  None
* @retval None
*/
void uart_write_str(uint8_t *paddr, uint16_t lenght)
{
  uint32_t index = 0;
  
  /* Send characters one per one, until last char to be sent */
  for (index = 0; index < lenght; index++)
  {
    /* Wait for TXE flag to be raised */
    while (!LL_LPUART_IsActiveFlag_TXE(LPUART1))
    {
    }
    /* Write character in Transmit Data register.
    TXE flag is cleared by writing data in TDR register */
    LL_LPUART_TransmitData8(LPUART1, paddr[index]);
  }
  
  /* Wait for TC flag to be raised for last char */
  while (!LL_LPUART_IsActiveFlag_TC(LPUART1))
  {
  }
}

/******************************************************************************/
/* Peripheral Interrupt Handlers                                              */
/* Add here the Interrupt Handlers for the used peripherals.                  */
/* For the available peripheral interrupt handler names,                      */
/* please refer to the startup file.                                          */
/******************************************************************************/
/**
  * Brief   This function handles LPUARTx Instance interrupt request.
  * Param   None
  * Retval  None
  */
void LPUART1_IRQHandler(void)
{
  /* Check RXNE_RXFNE flag value in ISR register */
  if(LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1) && LL_LPUART_IsEnabledIT_RXNE(LPUART1))
  {
    /* Call function in charge of handling Character reception */

  }
  else 
  {
    /* Call Error function */
  }
}




// serial printf   uint64_t %llu
static uint8_t printf_buffer[PRINT_BUF] = {0};
int COMPrintf(const char* fmt, ...)
{
	va_list ap;
	va_start(ap, fmt );
	//memset(printf_buffer,'\0',sizeof(printf_buffer));
	uint16_t len = vsprintf((char *)printf_buffer,fmt,ap);
	va_end( ap );

	//simulate_uart_write_fifo(printf_buffer,len);
	uart_write_str(printf_buffer, len);
	return len;   
}

int COMPrintf_hexdump(uint8_t *parr,uint8_t len)
{
	char my_buf[PRINT_BUF];
	if(len < ((PRINT_BUF-1) /5))
	{
			memset(my_buf,0,sizeof(my_buf));
			for(int i=0;i<len;i++)
			{
					if((i+1)!=len)
						sprintf(my_buf+5*i,"0x%02x ",parr[i]);
					else
						sprintf(my_buf+5*i,"0x%02x \n",parr[i]);
			}

			COMPrintf(my_buf);
	}  
	return len;
}

static void sys_alive_detect(void)
{
	COMPrintf("*");
}

driver_init("LOG", COMPrintf_init);

task_register("LOG", sys_alive_detect, 409600);

